#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include"threadpool.hpp"
#include"log.hpp"
#define NUM 1024

using namespace std;
namespace Server
{
    enum
    {
        USAGE_ERR=1,SOCK_ERR,BIND_ERR,LISTEN_ERR
    };
class tcpserver;
    class ThreadData
    {
public:
ThreadData( tcpserver* self,int psock):_this(self),_psock(psock){}
tcpserver* _this;
int _psock;
    };

class tcpserver
{
 
public:

tcpserver(const  uint16_t& port):_port(port),_listensock(-1){}

void initserver()
{
//1.创建套接字
_listensock=socket(AF_INET,SOCK_STREAM,0);
if(_listensock<0)
{
    logMessage(FATAL,"create listensocket error");
    exit(SOCK_ERR);
}
 logMessage(NORMAL, "create socket success: %d", _listensock);
//2.bind ip和port
struct sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port=htons(_port);
local.sin_addr.s_addr=INADDR_ANY;
if(bind(_listensock,(struct sockaddr*)&local,sizeof(local))<0)//绑定失败
{
    logMessage(FATAL,"bind error");
    exit(BIND_ERR);
}
 logMessage(NORMAL,"bind success");
//3.将套接字设置为监听模式
if(listen(_listensock,0)<0)
{
    logMessage(FATAL,"listen error");
    exit(LISTEN_ERR);
}
logMessage(NORMAL,"listen success");
}

void start()
{
     // signal(SIGCHLD, SIG_IGN);
    //threadPool<Task>::getthpptr()->run();
    while(true)
    {
        struct sockaddr_in cli;
        socklen_t len=sizeof(cli);
        bzero(&cli,len);

        int sock=accept(_listensock,(struct sockaddr*)&cli,&len);
        if(sock<0)
        {
            logMessage(FATAL,"accept client error");
            continue;
        }
        logMessage(NORMAL,"accept client success");

        cout<<"accept sock: "<<sock<<endl;
        // serviceIO(sock);//客户端串行版---阻塞在accept函数出
        // close(sock);

        //多进程版---
        //一个客户端占用一个文件描述符，原因在于孙子进程执行IO任务需要占用独立的文件描述符,而文件描述符是继承父进程的，而每次客户端进来都要占用新的文件描述符
        //因此若接收多个客户端不退出的话文件描述符会越来越少。
        pid_t id=fork();//创建子进程
        if(id==0)//子进程进入
        {
            close(_listensock);//子进程不需要用于监听因此关闭该文件描述符
            if(fork()>0)  exit(0);
// //子进程创建孙子进程，子进程直接退出，让孙子进程担任IO任务，且孙子进程成为孤儿进程被OS领养，
// //除非客户端退出IO任务结束否则该孤儿进程一直运行下去不会相互干扰,即并行完成服务器和客户端的通信

// //孙子进程
serviceIO(sock);
close(sock);
exit(0);
        }
        //父进程
        close(sock);//父进程不使用文件描述符就关闭
        pid_t ret=waitpid(id,nullptr,0);
        if(ret<0)
        {
            cout << "waitsuccess: " << ret << endl;
        }

//多线程版
// pthread_t pid;
// ThreadData* th=new ThreadData(this,sock);
// pthread_create(&pid,nullptr,start_routine,th);

//threadPool<Task>::getthpptr()->push(Task(sock,serviceIO));
    }
}

static void* start_routine(void* args)
{
    pthread_detach(pthread_self());//线程分离后让OS自动回收新线程
    ThreadData* ret=static_cast<ThreadData*>(args);
    ret->_this->serviceIO(ret->_psock);
    close(ret->_psock);
    delete ret;
    return nullptr;
} 

void serviceIO(int sock)
{
    char inbuffer[NUM];
    while(true)
    {
        ssize_t n=read(sock,inbuffer,sizeof(inbuffer)-1);
        if(n>0)
        {
            inbuffer[n]=0;
            cout<<"recv message: "<<inbuffer<<endl;
            string outb=inbuffer;
            string outbuffer=outb+"[server echo]";

            write(sock,outbuffer.c_str(),outbuffer.size());

        }
else
{
    logMessage(NORMAL,"client quit,i quit yep");
    break;
}
    }

}

~tcpserver(){}

private:
int _listensock;//用于监听服务器的sock文件描述符
uint16_t _port;//端口号
};

}